﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

using System.Net;

using System.IO;
using System.Security.Cryptography.X509Certificates;

namespace Clarendon.AzureBilling.Library
{
    /// <summary>
    /// This class is used to build queries and parse XML responses from the Management API 
    /// </summary>
    public static class QueryManager
    {
        /// <summary>
        /// This method makes a callback to an AsyncResponseParser and takes a service management request and certificate and sends a request to 
        /// the management endpoint
        /// </summary>
        public static void MakeASyncRequest(ServiceManagementRequest serviceManagementRequest, 
            string certificateFileUri, ServiceManager.AsyncResponseParser parser, ServiceManager.AsyncResponseException error)
        {
            var request = BuildAzureHttpRequest(serviceManagementRequest);

            if(serviceManagementRequest.Certificate == null)
                AddCertificateToRequest(certificateFileUri, request);
            else
            {
                request.ClientCertificates.Add(serviceManagementRequest.Certificate);
            }

            try
            {
                IAsyncResult result = request.BeginGetResponse(new AsyncCallback((asyncResult) =>
                {
                    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                    parser(response);

                    /* TODO: Put an event subscription in here */
                }), null);
            }
            catch (WebException ex)
            {
                if (error != null)
                    error(ex);
                else
                    throw;
            }
            
        }

        public static void MakeASyncRequest(ServiceManagementRequest serviceManagementRequest, 
            string certificateFileUri, ServiceManager.AsyncResponseParser parser)
        {
            MakeASyncRequest(serviceManagementRequest, certificateFileUri, parser, null);
        }

        #region Helper Methods

        /// <summary>
        /// Checks if a certificate exists and adds to the request
        /// </summary>
        private static void AddCertificateToRequest(string certificateFileUri, HttpWebRequest request)
        {
            if (!File.Exists(certificateFileUri))
            {
                throw new ApplicationException("Selected certificate file does not exist");
            }

            X509Certificate2 cert = new X509Certificate2(certificateFileUri);
            request.ClientCertificates.Add(cert);
        }

        /// <summary>
        /// Builds an Azure request which is then sent to the Management Portal 
        /// </summary>
        private static HttpWebRequest BuildAzureHttpRequest(ServiceManagementRequest serviceManagementRequest)
        {
            string optionalData = serviceManagementRequest.OptionalData != null
                                      ? "/" + serviceManagementRequest.OptionalData
                                      : String.Empty;
            string requestUriString = String.Format("{0}/{1}/{2}/{3}", serviceManagementRequest.BaseUri,
                                                    serviceManagementRequest.SubscriptionId,
                                                    serviceManagementRequest.ServiceType, 
                                                    serviceManagementRequest.OperationId);
            Uri requestUri = new Uri(requestUriString + optionalData);

            HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(requestUri);
            request.Headers.Add("x-ms-version", "2011-10-01");
            request.Method = serviceManagementRequest.HttpVerb ?? "GET";
            request.ContentType = "application/xml";

            if (serviceManagementRequest.Body != null)
            {
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(serviceManagementRequest.Body);
                request.ContentLength = bytes.Length;
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(bytes, 0, bytes.Length);
                }
            }

            return request;
        }

        #endregion

        /// <summary>
        /// Returns an Xml namespace + entity for the lookup
        /// </summary>
        public static XName BuildDefaultNamespaceXmlEntity(string entityName)
        {
            XNamespace ns = ServiceManager.DefaultWindowsAzureXmlNamespace;
            return ns + entityName;
        }
    }
}
